// Copyright (c) 2021 Presto Labs Pte. Ltd.
// Author: chensili

#pragma once

#include <memory>
#include <string>
#include <utility>

#include "coin2/base/proto_util.h"
#include "coin2/exchange/base/order/parser.h"
#include "coin2/exchange/factory/order/parser.h"
#include "coin2/exchange/base/order/symbol_cache.h"
#include "coin2/exchange/util/json_util.h"
#include "coin2/exchange/base/symbology/product_holder_manager.h"

using coin2::exchange::base::order::BaseParser;
using coin2::exchange::base::order::SymbologyCache;
using coin2::exchange::factory::order::CreateOrderParser;
using ProductHolderManager = coin2::exchange::base::symbology::ProductHolderManager;

namespace appcoin2::support::order {
class PyOrderParser {
 public:
  static PyOrderParser from_mea_str(const std::string& mea_str) {
    auto mea = MarketExchangeApi::FromString(mea_str);
    auto parser = CreateOrderParser(mea);
    parser->UpdateTimestamp(GetCurrentTimestamp());
    if (!parser) {
      throw std::runtime_error("CreateOrderParser fails" + mea_str);
    }
    return PyOrderParser(std::move(parser), mea);
  }

  std::string ParseBalance(const std::string data) {
    rapidjson::Document document;
    document.Parse<rapidjson::kParseNumbersAsStringsFlag>(data.c_str());
    if (document.HasParseError()) {
      throw std::runtime_error("Parsing Error: " + data);
    }
    auto account_balance = parser_->ParseBalance(document);
    auto account_balance_str = ProtoToJsonString(account_balance);
    return account_balance_str;
  }

  std::string ParsePosition(const std::string data) {
    rapidjson::Document document;
    document.Parse<rapidjson::kParseNumbersAsStringsFlag>(data.c_str());
    if (document.HasParseError()) {
      throw std::runtime_error("Parsing Error: " + data);
    }
    auto account_position = parser_->ParsePosition(document);
    auto account_position_str = ProtoToJsonString(account_position);
    return account_position_str;
  }

  void AddProduct(const std::string oss_config_str) {
    coin2::exchange::order::OrderSystemConfig oss_config;
    oss_config.ParseFromString(oss_config_str);
    auto products = ProductRequestsFromConfig(oss_config.mea(), oss_config.products());
    symcache_.set_mea(mea_);
    auto get_product_holder = [this](const coin2::exchange::base::symbology::IProduct& product, int64_t timestamp) {
      return product_holder_manager_.GetProductHolder(product, timestamp);
    };
    symcache_.SetGetProductHolder(get_product_holder);

    for (auto& prod : products) {
      symcache_.AddProduct(std::move(prod));
    }
    parser_->SetSymcache(&symcache_);
  }

  void SetUseCrossMode(bool use_cross_mode) {
    parser_->SetUseCrossMode(use_cross_mode);
  }

 private:
  PyOrderParser(std::unique_ptr<BaseParser> parser, MarketExchangeApi mea) :
      parser_(std::move(parser)),
      mea_(mea),
      product_holder_manager_(coin::proto::ProductHolderManagerConfig()) {}
  std::unique_ptr<BaseParser> parser_;
  MarketExchangeApi mea_;
  SymbologyCache symcache_;
  ProductHolderManager product_holder_manager_;
};

}  // namespace appcoin2::support::order
